home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Visual Cafe 3
/
Visual Cafe 3.ISO
/
Vcafe
/
Main.bin
/
JWrappingLabel.java
< prev
next >
Wrap
Text File
|
1998-09-26
|
11KB
|
395 lines
package com.symantec.itools.swing;
import java.awt.Graphics;
import java.awt.FontMetrics;
import java.awt.Dimension;
import java.awt.Label;
import java.beans.PropertyVetoException;
import java.beans.PropertyChangeListener;
import java.beans.VetoableChangeListener;
import java.beans.PropertyChangeEvent;
import com.sun.java.swing.JComponent;
import com.sun.java.swing.SwingConstants;
import com.symantec.itools.beans.VetoableChangeSupport;
import com.symantec.itools.beans.PropertyChangeSupport;
/**
* This class implements a multiple-line text label.
* It displays text on one or more lines, wrapping text
* as needed to fit in the available horizontal space.
*/
public class JWrappingLabel
extends JComponent
implements SwingConstants
{
/**
* The text string being displayed.
*/
protected String text = "";
/**
* The current text alignment.
* One of ALIGN_LEFT, ALIGN_CENTERED, or ALIGN_RIGHT.
* @see com.sun.java.swing.SwingConstants#LEFT
* @see com.sun.java.swing.SwingConstants#CENTER
* @see com.sun.java.swing.SwingConstants#RIGHT
*/
protected int align;
/**
* Constructs a default wrapping label. Default values are an empty text string
* and left alignment.
*/
public JWrappingLabel()
{
this("");
}
/**
* Constructs a wrapping label that displays the specified string.
* The label will default to left alignment.
*
* @param s string to be displayed in label
*/
public JWrappingLabel(String s)
{
this(s, LEFT);
}
/**
* Constructs wrapping label with the specified text and alignment.
*
* @param s the string to be displayed in label
* @param a the alignment, one of ALIGN_LEFT, ALIGN_CENTERED, or ALIGN_RIGHT
*
* @see com.symantec.itools.swing.Alignment
* @see com.symantec.itools.swing.Alignment#ALIGN_LEFT
* @see com.symantec.itools.swing.Alignment#ALIGN_CENTERED
* @see com.symantec.itools.swing.Alignment#ALIGN_RIGHT
*/
public JWrappingLabel(String s, int a)
{
try
{
setText(s);
}
catch(PropertyVetoException veto) {};
try
{
setTextAlignment(a);
}
catch(PropertyVetoException veto) {};
}
//--------------------------------------------------
// accessor members
//--------------------------------------------------
/**
* Gets the current text alignment setting.
*
* @return the current alignment, one of ALIGN_LEFT, ALIGN_CENTERED, or ALIGN_RIGHT
* @see #setTextAlignment
* @see com.symantec.itools.swing.Alignment
* @see com.symantec.itools.swing.Alignment#ALIGN_LEFT
* @see com.symantec.itools.swing.Alignment#ALIGN_CENTERED
* @see com.symantec.itools.swing.Alignment#ALIGN_RIGHT
*/
public int getTextAlignment()
{
return align;
}
/**
* Sets the text alignment.
*
* @param newAlignStyle the new alignment style, one of ALIGN_LEFT, ALIGN_CENTERED, or ALIGN_RIGHT
* @see #getTextAlignment
* @see com.symantec.itools.swing.Alignment
* @see com.symantec.itools.swing.Alignment#ALIGN_LEFT
* @see com.symantec.itools.swing.Alignment#ALIGN_CENTERED
* @see com.symantec.itools.swing.Alignment#ALIGN_RIGHT
* @exception PropertyVetoException
* if the specified property value is unacceptable
*/
public void setTextAlignment(int newAlignStyle)
throws PropertyVetoException
{
if (align != newAlignStyle)
{
Integer oldAlignStyleInt = new Integer(align);
Integer newAlignStyleInt = new Integer(newAlignStyle);
vetos.fireVetoableChange("textAlignment",oldAlignStyleInt,newAlignStyleInt);
align = newAlignStyle;
changes.firePropertyChange("textAlignment",oldAlignStyleInt,newAlignStyleInt);
repaint();
}
}
/**
* Gets the current label text.
*
* @return the label's text string
* @see #setText
*/
public String getText()
{
return text;
}
/**
* Sets the label text.
*
* @param s the new label text
*
* @see #getText
* @exception PropertyVetoException
* if the specified property value is unacceptable
*/
public void setText(String newText)
throws PropertyVetoException
{
if (!(text.equals(newText)))
{
String oldText;
oldText = text;
vetos.fireVetoableChange("text", oldText, newText);
text = newText;
changes.firePropertyChange("text", oldText, newText);
repaint();
}
}
//--------------------------------------------------
// event methods
//--------------------------------------------------
//--------------------------------------------------
// class methods
//--------------------------------------------------
//--------------------------------------------------
// member methods
//--------------------------------------------------
/**
* Returns an empty string.
* This is a standard Java AWT method which typically returns a string
* representing the state of this object.
*
* @return the empty string
*/
public String paramString()
{
//???RKM??? Why are we doing this ???
return "";
}
/**
* Paints this component using the given graphics context.
* This is a standard Java AWT method which typically gets called
* by the AWT to handle painting this component. It paints this component
* using the given graphics context. The graphics context clipping region
* is set to the bounding rectangle of this component and its [0,0]
* coordinate is this component's top-left corner.
*
* @param g the graphics context used for painting
* @see java.awt.Component#repaint
* @see java.awt.Component#update
*/
public void paintComponent(Graphics g)
{
if(text != null)
{
int x;
int y;
int boundx;
int boundy;
Dimension d;
int fromIndex = 0;
int pos = 0;
int bestpos;
String largestString;
String s;
// Set up some class variables
FontMetrics fm = getToolkit().getFontMetrics(getFont());
int baseline = fm.getMaxAscent();
// Get the maximum height and width of the current control
d = getSize();
boundx = d.width;
boundy = d.height;
// X and Y represent the coordinates of the upper left portion
// of the next text line.
x = 0;
y = 0;
// While we haven't passed the bottom of the label and we
// haven't run past the end of the string...
while((y + fm.getHeight()) <= boundy && fromIndex != -1)
{
// Automatically skip any spaces at the beginning of the line
while(fromIndex < text.length() && text.charAt(fromIndex) == ' ')
{
++fromIndex;
// If we hit the end of line while skipping spaces, we're done.
if (fromIndex >= text.length()) break;
}
// fromIndex represents the beginning of the line
pos = fromIndex;
bestpos = -1;
largestString = null;
while(pos >= fromIndex)
{
pos = text.indexOf(' ', pos);
// Couldn't find another space?
if(pos == -1)
{
s = text.substring(fromIndex);
}
else
{
s = text.substring(fromIndex, pos);
}
// If the string fits, keep track of it.
if (fm.stringWidth(s) < boundx)
{
largestString = s;
bestpos = pos;
// If we've hit the end of the string, use it.
if (pos == -1) break;
}
else
{
break;
}
++pos;
}
if(largestString == null)
{
//???RKM??? We should not do this - we can do it right
// Couldn't wrap at a space, so find the largest line
// that fits and print that. Note that this will be
// slightly off -- the width of a string will not necessarily
// be the sum of the width of its characters, due to kerning.
int totalWidth = 0;
int oneCharWidth = 0;
pos = fromIndex;
while (pos < text.length())
{
oneCharWidth = fm.charWidth(text.charAt(pos));
if ((totalWidth + oneCharWidth) >= boundx) break;
totalWidth += oneCharWidth;
++pos;
}
drawAlignedString(g, fm, baseline, text.substring(fromIndex, pos), x, y, boundx);
fromIndex = pos;
}
else
{
drawAlignedString(g, fm, baseline, largestString, x, y, boundx);
fromIndex = bestpos;
}
y += fm.getHeight();
}
// We're done with the font metrics...
fm = null;
}
}
/**
* Adds a listener for all event changes.
* @param PropertyChangeListener listener the listener to add.
* @see #removePropertyChangeListener
*/
public synchronized void addPropertyChangeListener(PropertyChangeListener listener)
{
changes.addPropertyChangeListener(listener);
}
/**
* Removes a listener for all event changes.
* @param PropertyChangeListener listener the listener to remove.
* @see #addPropertyChangeListener
*/
public synchronized void removePropertyChangeListener(PropertyChangeListener listener)
{
changes.removePropertyChangeListener(listener);
}
/**
* Adds a vetoable listener for all event changes.
* @param VetoableChangeListener listener the listener to add.
* @see #removeVetoableChangeListener
*/
public synchronized void addVetoableChangeListener(VetoableChangeListener listener)
{
vetos.addVetoableChangeListener(listener);
}
/**
* Removes a vetoable listener for all event changes.
* @param VetoableChangeListener listener the listener to remove.
* @see #addVetoableChangeListener
*/
public synchronized void removeVetoableChangeListener(VetoableChangeListener listener)
{
vetos.removeVetoableChangeListener(listener);
}
/**
* This helper method draws a string aligned the requested way.
* @param g the graphics context used for painting
* @param s the string to draw
* @param x the point to start drawing from, x coordinate
* @param y the point to start drawing from, y coordinate
* @param width the width of the area to draw in, in pixels
*/
protected void drawAlignedString(Graphics g, FontMetrics fm, int baseline, String s, int x, int y, int width)
{
int drawx = x;
int drawy = y + baseline;
if (align != LEFT)
{
int sw = fm.stringWidth(s);
if (align == CENTER)
drawx += (width - sw) / 2;
else if (align == RIGHT)
drawx = drawx + width - sw;
}
g.drawString(s, drawx, drawy);
}
private VetoableChangeSupport vetos = new VetoableChangeSupport(this);
private PropertyChangeSupport changes = new PropertyChangeSupport(this);
}